﻿namespace Sai.Cecil
{
	using Sai.Core.Introspection;
	using Mono.Cecil;
	using System.Collections.Generic;
	
	/// <summary>
	/// Factory type extension to build a declarations from equivalent mono definition objects.
	/// </summary>
	public static class TypeReferenceExtensions
	{
		/// <summary>
		/// Creates a type name from a mono TypeReference object.
		/// </summary>
		/// <param name="typeReference">The type reference.</param>
		/// <returns>The type name object.</returns>
		public static TypeName ToTypeName(this TypeReference typeReference)
		{
            Namespace ns = new Namespace(typeReference.Namespace);
            Name fixedUpTypeName = new Name(typeReference.Name);

			var genericType = typeReference as Mono.Cecil.GenericInstanceType;

			if (genericType == null)
			{
				if (typeReference.HasGenericParameters)
				{
					fixedUpTypeName = new Name(typeReference.GenericTypeName());
				}
                else if (typeReference.IsByReference)
                {
                    fixedUpTypeName = new Name(typeReference.ByReferenceTypeName());
                }
			}
			else
			{
				fixedUpTypeName = new Name(genericType.GenericTypeName());
			}

			return new TypeName(ns, fixedUpTypeName);
		}

		private static string GenericTypeName(this TypeReference typeReference)
		{
			return string.Format(
					"{0}<{1}>",
					typeReference.Name.NonGenericName(),
					string.Join(",", typeReference.GenericArguments()));
		}

        private static string ByReferenceTypeName(this TypeReference typeReference)
        {
            return typeReference.Name.NonByReferenceName();
        }

		/// <summary>
		/// Creates a list of generic arguments from generic instance type.
		/// </summary>
		/// <param name="git">The generic type.</param>
		/// <returns>A list of arguments.</returns>
		private static IEnumerable<string> GenericArguments(this TypeReference git)
		{
			var genericArgs = new List<string>();

			int count = git.GenericParameters.Count;

			if (count > 0)
			{
				foreach (var param in git.GenericParameters)
				{
					genericArgs.Add(param.Name);
				}
			}

			return genericArgs;
		}
	}
}
